#define NO_SYS_INFO

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <string.h>
#include <ctype.h>
#include <dirent.h>
#include <stdbool.h>
#include "debug.h"

#ifndef NO_SYS_INFO
#  include <sys/sysinfo.h>

typedef struct _info_sys_
{       /* CPU */
        char *cpu_name;             /* Apontador para nome do processador */
        int cpu_mhz;                /* Mhz do proceassador                */
        int cpu_cache;              /* Cache do cpu em kbs                */
        /* RAM */
        unsigned long ram_total;    /* Memoria ram total em bytes         */
        unsigned long ram_free;     /* Memoria ram livre em bytes         */
        unsigned long ram_used;     /* Memoria ram usada em bytes         */
        float pram_used;            /* Percentagem da memoria ram usada   */
        float pram_free;            /* Percentagem da memoria ram livre   */
        /* SWAP */
        unsigned long swap_total;   /* Memoria swap total em bytes        */
        unsigned long swap_free;    /* Memoria swap livre em bytes        */
        unsigned long swap_used;    /* Memoria swap usada em bytes        */
        float pswap_used;           /* Percentagem da memoria swap usada  */
        float pswap_free;           /* Percentagem da memoria swap livre  */
        /* UPTIME */
        long uptime;                /* Uptime total em segundos           */
        unsigned short procs;       /* Numero de processos                */
} SYS;

SYS *get_sys_info(void);
#endif

inline bool comp(char *, char *);
bool isstrnum(char *);
bool isnum(char);
bool compic(char *, char *);
bool isinsidestr(char *, char *);
bool isinsidestric(char *, char *);
bool compictk(char *, char *, int);
bool comptk(char *, char *, int);
char *getoken(char *, unsigned short, char);
int tknum(char *, char);
int tknumac(char *, char);
char *getokenac(char *, unsigned short, char, bool *);

static size_t strlen_i(short int *);
static int tknum_i(short int *, char);
static short int *getoken_i(short int *, unsigned short, char);

inline bool comp(char *s1, char *s2)
{
        short int counter=0;

        if (s1 == NULL || s2 == NULL) return false;
        if (strlen(s1) != strlen(s2)) return false;

        while (s1[counter] != '\0')
        {
                if (s1[counter] != s2[counter]) return false;
                counter++;
        }

        return true;
}

#ifndef NO_SYS_INFO
SYS *get_sys_info(void)
{
        FILE *cpu;
        SYS *sys;
        struct sysinfo sys_info;
        char ch,cht='\0';
        int grava=0;
        int count2=0;
        int count=0;
        size_t tell;
        size_t tamanho=16;

        sys=malloc(sizeof(*sys));
        if (sys == NULL)
                return NULL;

        sysinfo(&sys_info);

        sys->uptime=sys_info.uptime;
        sys->ram_total=sys_info.totalram;
        sys->ram_free=sys_info.freeram;
        sys->swap_total=sys_info.totalswap;
        sys->swap_free=sys_info.freeswap;

        sys->procs=sys_info.procs;

        sys->cpu_name=malloc(tamanho);
        if (sys->cpu_name == NULL)
                return NULL;

        sys->cpu_name[0]='\0';

        if ((cpu=fopen("/proc/cpuinfo","r")) != NULL)
        {
                count=0;
                while (fscanf(cpu,"%c",&ch) != EOF)
                {
                        if (count == 0) fseek(cpu,0,0);
                        tell=ftell(cpu);
                        fscanf(cpu,"model name : %c",&cht);
                        if (cht != '\0')
                        {
                                fseek(cpu,tell,0);
                                count=0;
                                while (fscanf(cpu,"%c",&ch) != EOF && count != 1)
                                {
                                        if (ch == ':')
                                        {
                                                grava=1;
                                                fseek(cpu,1,1);
                                                ch='\0';
                                        }
                                        if (ch == '\n') count=1;
                                        else
                                        {
                                                if (grava && ch != '\0')
                                                {
                                                        if (count2+1 > tamanho)
                                                        {
                                                                tamanho++;
                                                                sys->cpu_name=realloc(sys->cpu_name,tamanho);
                                                                if (sys->cpu_name == NULL)
                                                                        return NULL;
                                                        }
                                                        sys->cpu_name[count2]=ch;
                                                        count2++;
                                                }
                                        }
                                }
                                if (count2+1 > tamanho)
                                {
                                        tamanho++;
                                        sys->cpu_name=realloc(sys->cpu_name,tamanho);
                                        if (sys->cpu_name == NULL)
                                                return NULL;
                                }
                                sys->cpu_name[count2]='\0';
                                break;
                        }

                        count++;
                }

                fseek(cpu,0,0);
                count=0;
                while (fscanf(cpu,"%c",&ch) != EOF)
                {
                        if (count == 0) fseek(cpu,0,0);
                        fscanf(cpu,"cpu MHz             : %d.\n",&sys->cpu_mhz);
                        count++;
                }
                fseek(cpu,0,0);
                count=0;
                while (fscanf(cpu,"%c",&ch) != EOF)
                {
                        if (count == 0) fseek(cpu,0,0);
                        fscanf(cpu,"cache size  : %d KB\n",&sys->cpu_cache);
                        count++;
                }
                fclose(cpu);
        }
        count=0;

        sys->ram_used=sys->ram_total-sys->ram_free;
        sys->swap_used=sys->swap_total-sys->swap_free;

        /*Percentagens*/
        sys->pram_used= (float) sys->ram_used/ (float) sys->ram_total*100.0;
        sys->pram_free= (float) sys->ram_free/ (float) sys->ram_total*100.0;
        sys->pswap_used= (float) sys->swap_used/ (float) sys->swap_total*100.0;
        sys->pswap_free= (float) sys->swap_free/ (float) sys->swap_total*100.0;

        return sys;
}
#endif

bool isstrnum(char *str)
{
        long counter=0;

        if (!strlen(str)) return false;

        while (str[counter] != '\0')
        {
                if (!isnum(str[counter]))
                        return false;
                counter++;
        }

        return true;
}

bool isnum(char chr)
{
        if (chr >= '0' && chr <= '9') return true;
        return false;
}

/**
 * Compares two strings - case insensitive.
 *
 * @param str first string
 * @param str2 second string
 *
 * @return true if strings match, false otherwise
 */
bool compic(char *str, char *str2) /*comp ignore case*/
{
    long counter=0;

    if (str == NULL || str2 == NULL || strlen(str) != strlen(str2))
        return false;

    while (str[counter] != '\0')
    {
        if (tolower(str[counter]) != tolower(str2[counter])) return false;
        counter++;
    }

    return true; /* strings match */
}

bool isinsidestr(char *str, char *str2)
{
        long conter=0;
        long conter2=0;
        long conter3;
        long matches=0;
        size_t len1,len2;

        len1=strlen(str);
        len2=strlen(str2);

        if (str == NULL || str2 == NULL) return false;
        if (len1 == 0 || len2 == 0) return false;

        /*
        Maior - str2
        Menor - str
        */
        while (str2[conter] != '\0')
        {
                conter2=0;
                conter3=conter;
                matches=0;
                while (str2[conter3] != '\0')
                {
                        if (str2[conter3] == str[conter2]) matches++;
                        else matches=0;
                        if (matches == len1) return true; /*str esta' dentro de str2*/
                        conter3++;
                        conter2++;
                }
                conter++;
        }
        return false;
}

bool isinsidestric(char *str, char *str2)
{
        long conter=0;
        long conter2=0;
        long conter3;
        long matches=0;
        size_t len1,len2;

        len1=strlen(str);
        len2=strlen(str2);

        if (str == NULL || str2 == NULL) return false;
        if (len1 == 0 || len2 == 0) return false;

        /*
        Maior - str2
        Menor - str
        */
        while (str2[conter] != '\0')
        {
                conter2=0;
                conter3=conter;
                matches=0;
                while (str2[conter3] != '\0')
                {
                        if (tolower(str2[conter3]) == tolower(str[conter2])) matches++;
                        else matches=0;
                        if (matches == len1) return true; /*str esta' dentro de str2*/
                        conter3++;
                        conter2++;
                }
                conter++;
        }
        return false;
}

bool compictk(char *str, char *str2, int tk) /*comp ignore case token*/
{
        long counter=0;

        if (str == NULL || str2 == NULL) return false;
        /* so tem logica se str <= str2 */
        while ((str[counter] != '\0' || str2[counter] != '\0') && tk != 0)
        {
                if (tolower(str[counter]) != tolower(str2[counter])) return false;
                counter++;
                tk--;
        }

        return true; /*sao iguais*/
}

bool comptk(char *str, char *str2, int tk) /*comp case sensitive token*/
{
        long counter=0;

        if (str == NULL || str2 == NULL) return false;
        /* so tem logica se str <= str2 */
        while ((str[counter] != '\0' || str2[counter] != '\0') && tk != 0)
        {
                if (str[counter] != str2[counter]) return false;
                counter++;
                tk--;
        }

        return true; /*sao iguais*/
}

char *getoken(char *str, unsigned short tk, char sep)
{
        char *stret;
        unsigned short counter=0;
        unsigned short counter2=0;
        unsigned short mytk=1;
        bool wasvalid;

        wasvalid=(tk == mytk) ? true : false;
        if (strlen(str) == 0 || tk > tknum(str,sep) || str == NULL) return NULL;

        stret=malloc(strlen(str)+1);
        if (stret == NULL)
        {
                fprintf(stderr,"Erro na alocação de memória\n");
                exit(EXIT_FAILURE);
        }

        while (str[counter] != '\0')
        {
                if (str[counter] == sep && wasvalid)
                {
                        mytk++;
                        wasvalid=false;
                }
                if (str[counter] != sep) wasvalid=true;
                if (tk == mytk && wasvalid)
                {
                        stret[counter2]=str[counter];
                        counter2++;
                }
                counter++;
        }
        stret[counter2]='\0';
        return stret;
}

int tknum(char *str, char sep)
{
        unsigned short counter=0;
        unsigned short tknumber=0;
        bool wasvalid=false;

        if (str == NULL) return 0;

        while (str[counter] != '\0')
        {
                if (str[counter] == sep && wasvalid)
                {
                        tknumber++;
                        wasvalid=false;
                }
                if (str[counter] != sep) wasvalid=true;
                counter++;
        }
        if (wasvalid) tknumber++;
        return tknumber;
}

static size_t strlen_i(short int *str)
{
        size_t counter=0;

        while (str[counter] != 0)
                counter++;

        return counter;
}

static int tknum_i(short int *str, char sep)
{
        unsigned short counter=0;
        int tknumber=0;
        bool wasvalid=false;

        if (str == NULL)
                return 0;

        while (str[counter] != 0)
        {
                if (str[counter] == sep && wasvalid)
                {
                        tknumber++;
                        wasvalid=false;
                }

                if (str[counter] != sep)
                        wasvalid=true;

                counter++;
        }

        if (wasvalid)
                tknumber++;

        return tknumber;
}

static short int *getoken_i(short int *str, unsigned short tk, char sep)
{
        short int *stret;
        unsigned short counter=0;
        unsigned short counter2=0;
        unsigned short mytk=1;
        bool wasvalid;

        wasvalid=(tk == mytk) ? true : false;
        if (strlen_i(str) == 0
            || tk > tknum_i(str,sep)
            || str == NULL)
                return NULL;

        stret=malloc(sizeof(*stret)*(strlen_i(str)+1));
        if (stret == NULL)
        {
                fprintf(stderr,"Erro na alocação de memória\n");
                exit(EXIT_FAILURE);
        }

        while (str[counter] != 0)
        {
                if (str[counter] == sep && wasvalid)
                {
                        mytk++;
                        wasvalid=false;
                }

                if (str[counter] != sep)
                        wasvalid=true;

                if (tk == mytk && wasvalid)
                {
                        stret[counter2]=str[counter];
                        counter2++;
                }

                counter++;
        }
        stret[counter2]=0;
        return stret;
}

int tknumac(char *str, char sep)
{
        int counter=0;
        bool insidea=false;
        bool wasvalid=false;
        size_t str_l;
        int tknumber=0;

        if (str == NULL)
                return 0;

        str_l=strlen(str);

        while (str[counter] != '\0')
        {
                if (!insidea) /*Não está dentro de aspas*/
                {
                        if (counter == 0
                            && str[counter] == '\"')
                                insidea=true;
                        else if (str[counter] == '\"'
                                 && str[counter-1] == sep)
                                insidea=true;
                }
                else /*Está dentro de aspas*/
                {
                        if (counter == str_l-1
                            && str[counter] == '\"')
                                insidea=false;
                        else if (str[counter] == '\"'
                                 && str[counter+1] == sep)
                                insidea=false;
                }

                if (!insidea
                     && str[counter] == sep
                     && wasvalid)
                {
                        tknumber++;
                        wasvalid=false;
                }

                if (str[counter] != sep)
                        wasvalid=true;

                counter++;
        }

        if (wasvalid)
                tknumber++;

        return tknumber;
}

char *getokenac(char *str, unsigned short tk, char sep, bool *error)
{
        char *cret;
        short int *istr;
        short int *ret;
        int counter=0;
        int counter2=0;
        bool insidea=false;
        size_t str_l;

        str_l=strlen(str);

        *error=false;

        if (str_l == 0
            || tk > tknumac(str,sep)
            || str == NULL)
                return NULL;

        istr=malloc(sizeof(*istr)*(str_l+1));

        while (str[counter] != '\0')
        {
                istr[counter]=str[counter];

                counter++;
        }

        counter=0;
        while (str[counter] != '\0')
        {
                if (!insidea) /*Não está dentro de aspas*/
                {
                        if (str[counter] == '\"')
                        {
                                if (counter == 0)
                                {
                                        insidea=true;
                                        istr[counter]=-2;
                                }
                                else if (str[counter-1] == sep)
                                {
                                        insidea=true;
                                        istr[counter]=-2;
                                }
                        }
                }
                else /*Está dentro de aspas*/
                {
                        if (str[counter] == '\"')
                        {
                                if (counter == str_l-1)
                                {
                                        insidea=false;
                                        istr[counter]=-2;
                                }
                                else if (str[counter+1] == sep)
                                {
                                        insidea=false;
                                        istr[counter]=-2;
                                }
                        }
                }

                if (insidea
                    && str[counter] == sep)
                        istr[counter]=-1;

                counter++;
        }

        istr[counter]=0;

        if (insidea)
        {
                *error=true;
                free(istr);

                return NULL;
        }

        ret=getoken_i((istr[0] == sep) ? &istr[1] : istr,tk,sep);

        free(istr);

        if (ret == NULL)
                return NULL;

        cret=malloc(strlen_i(ret)+1);

        counter=0;

        while (ret[counter] != 0)
        {
                if (ret[counter] != -2)
                        cret[counter2++]=(char) (ret[counter] == -1) ? sep : ret[counter];

                counter++;
        }
        cret[counter2]='\0';

        return cret;
}
